/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.tnmk.worktime.gui;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.SortOrder;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.DefaultTableModel;
import org.joda.time.DateTime;
import org.tnmk.worktime.gui.history.filter.SpendFilter;
import org.tnmk.worktime.gui.tbl.CheckBoxImageHeaderRenderer;
import org.tnmk.worktime.gui.tbl.GroupRowsCellRenderer;
import org.tnmk.worktime.gui.tbl.SelectCellEditorRenderer;
import org.tnmk.worktime.gui.utils.JTableUtils;
import org.tnmk.worktime.service.action.Action;
import org.tnmk.worktime.service.dao.entry.SessionEntry;
import org.tnmk.worktime.service.dao.entry.SpendEntry;
import org.tnmk.worktime.service.model.SessionModel;
import org.tnmk.worktime.utils.NumUtils;

/**
 *
 * @author Administrator
 */
public class SpendAnalysisController {
  
  public static final int COL_INTIME = 0;
  public static final int COL_SPEND_NOTE = 1;
  public static final int COL_SPEND_COST = 2;
  public static final int COL_EXT = 3;
  public static final String EXTKEY_SPEND_ID = "spendId";
  public static final String EXTKEY_ROW_SELECTED = "rowSelected";
  public static final Boolean ROW_SELCTED_DEFAULT = true;
  private final MainFrame frame;
  
  public SpendAnalysisController(MainFrame frame) {
    this.frame = frame;
  }
  
  public void initGUI() {
    Border defaultTextboxBorder = UIManager.getBorder("TextField.border");//frame.jtxtBeginDateFilter.getBorder();
    frame.jpanSpendSearchInput.setBorder(defaultTextboxBorder);
    
    final JTable jtbl = frame.getJtblSpendAnalysis();
    //Table sort
    jtbl.setAutoCreateRowSorter(true);
    JTableUtils.sortColumn(jtbl, COL_INTIME, SortOrder.DESCENDING);
    JTableUtils.sortColumn(jtbl, COL_EXT, false);

    final CheckBoxImageHeaderRenderer checkBoxHeader = new CheckBoxImageHeaderRenderer(jtbl, COL_EXT);
    checkBoxHeader.setCheckboxAction(new Action() {
      @Override
      public void perform() {
        boolean selected = checkBoxHeader.isSelected();
        checkboxToAllRows(selected);
        calculateSumMoney();
      }
    });

    //Table format
    JTableUtils.setDateFormat(jtbl, COL_INTIME);
    JTableUtils.addRenderer(jtbl, COL_INTIME, new GroupRowsCellRenderer());
    JTableUtils.setNumberFormat(jtbl, COL_SPEND_COST);
    
    //Table text editor
    jtbl.getDefaultEditor(Object.class).addCellEditorListener(new CellEditorListener() {
      @Override
      public void editingCanceled(ChangeEvent e) {
      }
      
      @Override
      public void editingStopped(ChangeEvent e) {
        updateSpendEntry();
      }
    });

    //Table select row
    final SelectCellEditorRenderer selectRowEditor = new SelectCellEditorRenderer(EXTKEY_ROW_SELECTED);
    JTableUtils.setCell(jtbl, COL_EXT, selectRowEditor, selectRowEditor);
    selectRowEditor.setSelectAction(new Action() {
      @Override
      public void perform() {
//        int slcRow = jtbl.getSelectedRow();
        calculateSumMoney();
      }
    });
    
  }
  
  void updateSpendEntry() {
    int row = frame.getJtblSpendAnalysis().getSelectedRow();
    if (row < 0) {
      row = frame.getJtblSpendAnalysis().getEditingRow();
    }
    SessionModel viewModel = frame.getDetailController().getViewModel();
    SpendEntry entry = toFilteredSpendEntry(row);
    if (viewModel.getId().equals(entry.getSessionId())) {
      int spendIndex = ControllerHelper.findSpendInSessionViewModel(viewModel, entry.getId());
      viewModel.getMoneySpend().getItems().set(spendIndex, entry);
      frame.getService().addOrUpdateSessionAndSpends(viewModel);
    } else {
      frame.getService().addOrUpdateSpendAndCorrespondingSession(entry);
    }
  }

  /**
   * Search in current scope of history
   */
  public void filterSpendInCurrentFilteredSessions() {
    //Standarlize filter string
    String strFilter = frame.jtxtSpendSearch.getText();
    SpendFilter filter = new SpendFilter(strFilter);
    
    JTable jtbl = frame.getJtblSpendAnalysis();
    //Filter table data
    DefaultTableModel tblModel = (DefaultTableModel) jtbl.getModel();
    tblModel.setRowCount(0);//clear old table
    List<SessionEntry> sessions = frame.historyController.loadFilteredSessions();
    for (SessionEntry session : sessions) {
      List<SpendEntry> spendEntries = session.getMoneySpend().getItems();
      for (SpendEntry iSpend : spendEntries) {
        String spendNote = iSpend.getNote();
        if (spendNote != null && !spendNote.isEmpty() && filter.accept(spendNote)) {
          Object[] row = toFilteredSpendRow(session, iSpend);
          tblModel.addRow(row);
        }
      }
    }

    //Re-calculate sum money
    calculateSumMoney();
  }
  
  private void calculateSumMoney() {
    JTable jtbl = frame.getJtblSpendAnalysis();
    long sumMoney = 0;
    int rowCount = jtbl.getRowCount();
    for (int i = 0; i < rowCount; i++) {
      Boolean selected = isSelectedRow(jtbl, i);
      if (selected) {
        Long cost = getCostInRow(jtbl, i);
        sumMoney += cost;
      }
    }
    String strSumMoney = NumUtils.toString(sumMoney);
    JTableUtils.setHeader(jtbl, COL_SPEND_COST, strSumMoney);
//    frame.jtxtSumFilteredSpend.setText(strSumMoney);
  }

  /**
   * @param tblRow this is row on current table, not row of table model.
   * @return
   */
  public SpendEntry toFilteredSpendEntry(int tblRow) {
    JTable jtbl = frame.getJtblSpendAnalysis();
//    Object valSessionInTime = jtbl.getValueAt(tblRow, COL_INTIME);
    Map<String, Object> valExtra = (Map) jtbl.getValueAt(tblRow, COL_EXT);
    Object valSpendNote = jtbl.getValueAt(tblRow, COL_SPEND_NOTE);
    Object valSpendId = valExtra.get(EXTKEY_SPEND_ID);
    Long cost = getCostInRow(jtbl, tblRow);
    Integer id = (Integer) valSpendId;//NumUtils.toLong(valSpendId).intValue();
    SpendEntry e = frame.getService().findSpend(id);
    e.setCost(cost);
    e.setNote((String) valSpendNote);
    return e;
  }
  
  private Long getCostInRow(JTable jtbl, int tblRow) {
    Object valSpendCost = jtbl.getValueAt(tblRow, COL_SPEND_COST);
    Long cost = NumUtils.toLong(valSpendCost);
    return cost;
  }

  /**
   * @param jtbl SpendAnalysisTable
   * @param tblRow row on view of table, not row on model of table
   * @return
   */
  protected static Boolean isSelectedRow(JTable jtbl, int tblRow) {
    Map<String, Object> valExtra = (Map) jtbl.getValueAt(tblRow, COL_EXT);
    Object selectedVal = valExtra.get(EXTKEY_ROW_SELECTED);
    if (selectedVal == null) {
      return ROW_SELCTED_DEFAULT;
    }
    return (Boolean) selectedVal;
  }
  
  protected static void selectedRow(JTable jtbl, int tblRow) {
    Map<String, Object> valExtra = (Map) jtbl.getValueAt(tblRow, COL_EXT);
    Object selectedVal = valExtra.get(EXTKEY_ROW_SELECTED);
    if (selectedVal == null) {
      valExtra.put(EXTKEY_ROW_SELECTED, false);
    } else {
      Boolean selected = !((Boolean) selectedVal);
      valExtra.put(EXTKEY_ROW_SELECTED, selected);
    }
  }
  
  protected void checkboxToAllRows(boolean value) {
    JTable jtbl = frame.getJtblSpendAnalysis();
    int rowCount = jtbl.getRowCount();
    for (int i = 0; i < rowCount; i++) {
      Map<String, Object> valExtra = (Map) jtbl.getValueAt(i, COL_EXT);
      valExtra.put(EXTKEY_ROW_SELECTED, value);
    }
  }
  
  protected static Object[] toFilteredSpendRow(SessionEntry session, SpendEntry spend) {
    Map<String, Object> ext = new HashMap<>();
    ext.put(EXTKEY_SPEND_ID, spend.getId());
    ext.put(EXTKEY_ROW_SELECTED, ROW_SELCTED_DEFAULT);
    Object[] rs = new Object[]{session.getInTime(), spend.getNote(), spend.getCost(), ext};
    return rs;
  }
  
  public Map<SessionEntry, List<SpendEntry>> loadAllSpendOfFilteredSessions() {
    Map<SessionEntry, List<SpendEntry>> rs = new HashMap<>();
//    List<SpendEntry> spendEntries = new ArrayList<>();
    List<SessionEntry> sessions = frame.historyController.loadFilteredSessions();
    for (SessionEntry session : sessions) {
      rs.put(session, session.getMoneySpend().getItems());
    }
    return rs;
  }

  public MainFrame getFrame() {
    return frame;
  }
//  public static class ModelRow() {
//    private Map<String, Object> valExtra;
//    private Long cost;
//    private Integer id;
//    private String note;
//    private DateTime sessionInTime;
//    public ModelRow(){}
//  }
}
